package org.bdware.doaclient;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.apache.log4j.Logger;
import org.bdware.doip.core.doipMessage.DoipMessage;
import org.bdware.doip.core.model.digitalObject.DigitalObject;
import org.bdware.doip.core.model.digitalObject.DoType;
import org.bdware.doip.core.model.digitalObject.Element;
import org.bdware.irp.stateinfo.DoStateInfo;
import org.bdware.doip.core.model.metadata.SearchParameter;
import org.bdware.doip.core.utils.DoipGson;
import org.bdware.doip.core.utils.GlobalConfigurations;
import org.bdware.irp.client.GlobalIrpClient;

import java.util.Scanner;

public class CMDClient {

    public static final String certPath = "keys/dou.TEST.keystore";
    public static final String cerPWD = "123456";
    public static final String userHandle = "86.5000.470/dou.TEST";
    public static final String LHS_Address = "http://39.104.122.7:10001/";
    public static Logger logger = Logger.getLogger(CMDClient.class);

    public static void main(String[] args) {

        DOAClientForCMD client = new DOAClientForCMD(certPath,cerPWD,userHandle,LHS_Address);
        Scanner reader = new Scanner(System.in);
        while(true) {
            showHelp();
            try {
                args = reader.nextLine().split(" ");
                long s = System.currentTimeMillis();
                DoipMessage repMsg = null;
                if (checkArgs(args)) {
                    switch (args[0]) {
                        case "hello":
                            // example: hello 86.5000.470/doip.localTlsRegistry[86.5000.470/doip.localTcpRepo]
                            repMsg = client.hello(args[1]);
                            break;
                        case "list":
                            // example: list 86.5000.470/do.hello
                            repMsg = client.listOperations(args[1]);
                            break;
                        case "create":
                            // example: create 86.5000.470/doip.localTcpRepo
                            String repoID = args[1];
                            if(!repoID.contains("Cordra"))
                                repMsg = client.create(args[1],getCordraDO());
                            else{
                                repMsg = client.create(args[1],getCordraDO());
                                JsonObject jo = new Gson().fromJson(repMsg.body.getDataAsJsonString(),JsonObject.class);
                                DoStateInfo doHr = new DoStateInfo(GlobalConfigurations.userID,args[1]);
                                doHr.identifier = jo.get("id").getAsString();
                                logger.info("Successful register DO: " + GlobalIrpClient.getGlobalClient().reRegister(doHr));
                            }
                            break;
                        case "retrieve":
                            // example: retrieve 86.5000.470/do.hello
                            String element = args.length>3 ? args[2]:null;
                            repMsg = client.retrieve(args[1],element,true);
                            break;
                        case "update":
                            // example: update 86.5000.470/do.hello
                            DigitalObject tempDO = getUpdateDO(args[1]);
                            repMsg = client.update(args[1],tempDO);
                            break;
                        case "delete":
                            // example: delete 86.5000.470/do.hello
                            repMsg = client.delete(args[1]);
                            break;
                        case "index":
                            // example: index 86.5000.470/doip.localTlsRegistry 86.5000.470/do.hello description
                            repMsg = client.create(args[1],getTestMetadata(args[2],args[3]));
                            break;
                        case "search":
                            // example: search 86.5000.470/doip.localTlsRegistry keywords
                            String registryID = args[1];
                            String query = args[2];
                            SearchParameter sp = SearchParameter.getDefaultParameter();
                            sp.query = query;
                            repMsg = client.search(sp, registryID);
                            break;
                        case "exit":
                            System.exit(0);
                        default: showError();
                    }
                    System.out.println(args[0] + " done in " + (System.currentTimeMillis() - s) + "ms");
                    printResponse(repMsg);
                }
                else
                    showError();
            }
            catch (Exception ex) {
                System.out.println("Exception happened during excution: " + ex.getMessage());
            }
        }


    }



    private static void printResponse(DoipMessage repMsg) {
        if(repMsg == null) {
            logger.info("response: NULL!!");
            return;
        }
        logger.info("Response attributes: " + new String(repMsg.header.parameters.toByteArray()));
        logger.info("Response body: " + repMsg.body.getDataAsJsonString());
    }


    public static void showHelp() {
        System.out.println("usage:");
        System.out.println("       hello RepoID");
        System.out.println("       list DoID");
        System.out.println("       create RepoID");
        System.out.println("       retrieve DoID [elementId]");
        System.out.println("       update DoID");
        System.out.println("       delete DoID");
        System.out.println("       index registryID doID description");
        System.out.println("       search registryID keyword //avaiable registry 86.5000.470/doip.CloudTlsRegistry");
        System.out.println("       exit");
    }

    public static void showError() {
        System.out.println("Arguments error!");
    }

    public static boolean checkArgs(String[] args) {
        if (args.length < 1)
            return true;
        for(String arg : args)
            if (arg.equals(""))
                return false;
        switch (args[0]) {
            case "hello":
            case "create":
            case "update":
            case "delete":
            case "list":
                if (args.length != 2)
                    return false;
                break;
            case "search":
                if (args.length != 3)
                    return false;
                break;
            case "index":
                if (args.length != 4)
                    return false;
                break;
            case "retrieve":
                if (args.length < 2 || args.length > 3)
                    return false;
                break;
            case "exit":
                return true;
            default:
                return false;
        }
        return true;
    }

    public static DigitalObject getCreateDO(){
        DigitalObject digitalObject = new DigitalObject("", DoType.DO);
        digitalObject.addAttribute("content","helloWorld");
        Element e = new Element("hello","String");
        String data = "world";
        for(int i=0;i<10;i++) data = data + " world";
        e.setData(data.getBytes());
        digitalObject.addElements(e);
        logger.info("use default digital object, type: 0.Type/DO ");
        logger.info("DO attributes: " + DoipGson.getDoipGson().toJson(digitalObject.attributes));
        logger.info("Element: " + e.id + "; content: " + new String(e.getData()));
        return digitalObject;
    }

    private static DigitalObject getCordraDO() {
        JsonObject jo = new JsonObject();
        jo.addProperty("name","HelloWorld");
        jo.addProperty("description","hello world: DOIP working group!");

        DigitalObject digitalObject = new DigitalObject("", DoType.DO);
        digitalObject.addAttribute("content",jo);

        logger.info("use default digital object, type: 0.Type/DO ");
        logger.info("DO attributes: " + DoipGson.getDoipGson().toJson(digitalObject.attributes));
        return digitalObject;
    }

    public static DigitalObject getUpdateDO(String handle){
        DigitalObject digitalObject = new DigitalObject(handle, DoType.DO);
        digitalObject.addAttribute("content","hello updated");
        Element e = new Element("hello","String");
        String data = "updated";
        for(int i=0;i<10;i++) data = data + " updated";
        e.setData(data.getBytes());
        digitalObject.addElements(e);
        logger.info("use default digital object, type: 0.Type/DO ");
        logger.info("DO attributes: " + DoipGson.getDoipGson().toJson(digitalObject.attributes));
        logger.info("Element: " + e.id + "; content: " + new String(e.getData()));
        return digitalObject;
    }

    public static DigitalObject getTestMetadata(String doi, String description){
        DigitalObject digitalObject = new DigitalObject(doi, DoType.Metadata);
        digitalObject.addAttribute("desc",description);
        logger.info("Create digital object, type: 0.Type/DO.Metadata ");
        logger.info("DO id: " + doi);
        logger.info("DO attributes: " + DoipGson.getDoipGson().toJson(digitalObject.attributes));
        return digitalObject;
    }

}
